
#include "IGlobal.h"
#include "IMetaTypes.h"
#include "ILibStdio.h"
#include "ILibMath.h"

#include "member_BScript.h"
#include "member_BSource.h"

using namespace BWE;

BMap<BString, BClassHolder>	member_BScript::basicClassMap;
BMap<BString, BClassHolder>	member_BScript::basicTemplateMap;

member_BScript::member_BScript(BScript* script)
{
	boss = script;
	error = false;
	breaked = false;
	running = false;
	debugging = false;
	global = -1;
	current = -1;
	pausedHandle = 0;

	static bool basicInited = false;
	if (!basicInited)
	{
		if (BClass* cls = CreateBoolClass())
		{
			basicClassMap["bool"] = cls;
			class_member(cls)->meta = true;
		}
		if (BClass* cls = CreateIntClass())
		{
			basicClassMap["int"] = cls;
			class_member(cls)->meta = true;
		}
		if (BClass* cls = CreateLongClass())
		{
			basicClassMap["long"] = cls;
			class_member(cls)->meta = true;
		}
		if (BClass* cls = CreateFloatClass())
		{
			basicClassMap["float"] = cls;
			class_member(cls)->meta = true;
		}
		if (BClass* cls = CreateDoubleClass())
		{
			basicClassMap["double"] = cls;
			class_member(cls)->meta = true;
		}
		if (BClass* cls = CreateStringClass())
		{
			basicClassMap["string"] = cls;
			class_member(cls)->meta = true;
		}
		if (BClass* cls = CreateArrayTemplate())
		{
			basicTemplateMap["Array"] = cls;
		}
		basicInited = true;
	}

#ifdef linux
	if (0 != pthread_cond_init(&thread_cond, 0))
	{
		errorMessage() << "thread error : failed to init thread cond.";
		boss->emit(Signal_Error, message);
		return;
	}
	if(0 != pthread_mutex_init(&thread_mutex, 0))
	{
		errorMessage() << "thread error : failed to init thread cond.";
		boss->emit(Signal_Error, message);
		return;
	}
#endif
}
member_BScript::~member_BScript()
{

}

bool member_BScript::include(const BString& libname)
{
	if (presets.includes.contain(libname))
		return true;
	if (libname == "cstdio")
	{
		presets.includes.insert(libname);
		boss->regist("print(string)", print);
		return true;
	}
	if (libname == "cmath")
	{
		presets.includes.insert(libname);
		boss->regist("short abs(short)", short_abs);
		boss->regist("int abs(int)", int_abs);
		boss->regist("long abs(long)", long_abs);
		boss->regist("float abs(float)", float_abs);
		boss->regist("double abs(double)", double_abs);
		return true;
	}
	if (libname == "cstring")
	{
		presets.includes.insert(libname);
		return true;
	}
	return false;
}

BString& member_BScript::errorMessage(BExp* exp)
{
	error = true;
	if (message.empty())
	{
		message = new BString();
	}
	BString& text = message;
	text.reset();
	if (exp)
	{
		text << exp->info << " : ";
	}
	text << "error : ";
	return text;
}
void member_BScript::sourceMessage(const BValue& value)
{
	error = true;
	if (message.empty())
	{
		message = new BString();
	}
	BString& text = message;
	text << (const BString&)value << '\n';
	boss->emit(Signal_Message, value);
}

void member_BScript::combine()
{
	includes.clear();
	declares.clear();
	functionMap.clear();
	classMap.clear();
	for (int i = 0; i < sources.size(); i++)
	{
		const BSource* source = sources[i];
		for (int i = 0; i < source_member(source)->includes.size(); i++)
		{
			BExp* exp = source_member(source)->includes[i];
			for (int i = 0; i < includes.size(); i++)
			{
				BExp* inc = includes[i];
				if (inc->name == exp->name)
				{
					exp = 0;
					break;
				}
			}
			if (exp)
			{
				includes.append(exp);
			}
		}
		for (int i = 0; i < source_member(source)->declares.size(); i++)
		{
			BExp* exp = source_member(source)->declares[i];
			for (int i = 0; i < includes.size(); i++)
			{
				BExp* decl = includes[i];
				if (decl->name == exp->name)
				{
					exp = 0;
					break;
				}
			}
			if (exp)
			{
				declares.append(exp);
			}
		}
		for (auto fit = source_member(source)->functionMap.begin(); fit.valid(); fit++)
		{
			const BString& funcName = fit.key();
			Function* function = fit.value();
			if (function->sfunc->subs.empty())
				continue;
			if (this->functionMap.contain(funcName))
			{
				errorMessage(function->sfunc) << "Link : function " << funcName << " is redefined.";
				boss->emit(Signal_Message, message);
				continue;
			}
			this->functionMap.insert(funcName, *fit);
		}
		for (auto cit = source_member(source)->classMap.begin(); cit.valid(); cit++)
		{
			const BString& className = cit.key();
			BClass* cls = classMap[className];
			if (cls)
			{
				BMap<BString, MethodHolder>& methodMap = class_member(cls)->methodMap;
				BClass* cls = cit.value();
				for (auto it = class_member(cls)->methodMap.begin(); it.valid(); ++it)
				{
					const BString& name = it.key();
					Method* method = *it;
					if (method->value.empty())
						continue;
					if (method->value == 0)
						continue;
					BExp* sfunc0 = method->value;
					BExp* sfunc1 = methodMap(name)->value;
					if (sfunc0->info == sfunc1->info)
						continue;
					if (methodMap.contain(name))
					{
						errorMessage(method->value) << "Link : method " << name << " is redefined.";
						boss->emit(Signal_Message, message);
						continue;
					}
					methodMap[name]->value = method->value;
				}
			}
			else
			{
				classMap[className] = cit.value();
			}
		}
	}
}
void member_BScript::flatten()
{
	sequence.clear();
	for (int i = 0; i < includes.size(); i++)
	{
		BExp* inc = includes[i];
		flatten(inc);
	}
	for (int i = 0; i < declares.size(); i++)
	{
		BExp* decl = declares[i];
		flatten(decl);
	}
	BExp* none = new BExp(Syntax_None);
	sequence.append(none);
	for (auto fit = this->functionMap.begin(); fit.valid(); fit++)
	{
		Function* function = *fit;
		if (function->sfunc)
		{
			function->line = sequence.size();
			flatten(function->sfunc);
		}
	}
	for (auto it = this->classMap.begin(); it.valid(); ++it)
	{
		BClass* cls = it.value();
		BExp* exp = new BExp(Syntax_Class);
		exp->name = it.key();
		for (int i = 0; i < class_member(cls)->inherits.size(); i++)
		{
			BExp* inherit = class_member(cls)->inherits[i];
			inherit->info.clear();
			inherit->value.clear();
			inherit->subs.clear();
			inherit->params.clear();
			inherit->value = boss->findClass(inherit->type);
			exp->params.append(inherit);
		}
		for (auto vit = class_member(cls)->variantMap.begin(); vit.valid(); ++vit)
		{
			BVariant& var = vit.value();
			BExp* decl = var.value();
			decl->info.clear();
			decl->value.clear();
			decl->subs.clear();
			decl->params.clear();
			exp->params.append(decl);
		}
		sequence.append(exp);
		for (auto mit = class_member(cls)->methodMap.begin(); mit.valid(); ++mit)
		{
			Method* method = mit.value();
			if (BExp* sfunc = method->value)
			{
				method->line = sequence.size();
				flatten(sfunc);
			}
			if (method->virt)
			{
				BExp* vfunc = new BExp(Syntax_Method);
				vfunc->type = method->type;
				vfunc->name = mit.key();
				vfunc->value = method->value;
				exp->params.append(vfunc);
			}
		}
	}
	none->value = sequence.size();
}
void member_BScript::flatten(BExp* exp)
{
	switch (exp->syntax)
	{
	case Syntax_None:
	{
		for (int i = 0; i < exp->subs.size(); i++)
		{
			flatten(exp->subs[i]);
		}
		break;
	}
	case Syntax_Include:
	{
		exp->info.clear();
		exp->subs.clear();
		exp->params.clear();
		sequence.append(exp);
		break;
	}
	case Syntax_Value:
	{
		sequence.append(exp);
		break;
	}
	case Syntax_Name:
	{
		if (exp->subs.size())
		{
			for (int i = 0; i < exp->subs.size(); i++)
				exp->name << exp->subs[i]->name << '.';
			exp->name -= '.';
			exp->subs.clear();
		}
		sequence.append(exp);
		break;
	}
	case Syntax_Self:
	{
		if (exp->subs.size())
		{
			for (int i = 0; i < exp->subs.size(); i++)
				exp->name << exp->subs[i]->name << '.';
			exp->name -= '.';
			exp->subs.clear();
		}
		sequence.append(exp);
		break;
	}
	case Syntax_Decl:
	{
		sequence.append(exp);
		for (int i = 0; i < exp->subs.size(); i++)
		{
			flatten(exp->subs[i]);
		}
		exp->subs.clear();
		exp->params.clear();
		break;
	}
	case Syntax_Call:
	{
		if (exp->subs.size())
		{
			for (int i = 0; i < exp->subs.size(); i++)
			{
				flatten(exp->subs[i]);
			}
			exp->subs.clear();
		}
		if (Function* func = exp->value)
		{
			if (exp->type.size())
			{
				BExp* res = new BExp();
				res->syntax = Syntax_Value;
				res->type = exp->type;
				sequence.append(res);
			}
		}
		if (exp->params.size())
		{
			for (int i = 0; i < exp->params.size(); i++)
			{
				flatten(exp->params[i]);
			}
			exp->params.clear();
		}
		sequence.append(exp);
		break;
	}
	case Syntax_Opera:
	{
		if (exp->params.size())
		{
			for (int i = 0; i < exp->params.size(); i++)
			{
				flatten(exp->params[i]);
			}
			exp->params.clear();
		}
		sequence.append(exp);
		break;
	}
	case Syntax_Begin:
	{
		sequence.append(exp);
		break;
	}
	case Syntax_End:
	{
		sequence.append(exp);
		break;
	}
	case Syntax_Return:
	{
		if (BExp* last = exp->params.last())
		{
			flatten(last);
			exp->params.clear();
		}
		sequence.append(exp);
		break;
	}
	case Syntax_If:
	{
		sequence.append(new BExp(Syntax_Begin));
		flatten(exp->params.first());
		sequence.append(exp);
		for (int i = 0; i < exp->subs.size(); i++)
		{
			flatten(exp->subs[i]);
		}
		if (exp->params.size() > 1)
		{
			BExp* prev = exp;
			for (int i = 1; i < exp->params.size(); i++)
			{
				BExp* next = exp->params[i];
				sequence.append(next);
				prev->value = sequence.size();
				for (int s = 0; s < next->subs.size(); s++)
				{
					flatten(next->subs[s]);
				}
				next->subs.clear();
				prev = next;
			}
			prev->value = sequence.size();
		}
		else
		{
			exp->value = sequence.size();
		}
		sequence.append(new BExp(Syntax_End));
		exp->params.clear();
		exp->subs.clear();
		break;
	}
	case Syntax_While:
	{
		int loop = sequence.size();
		{
			sequence.append(new BExp(Syntax_Begin, loop));
			flatten(exp->params.first());
			sequence.append(exp);
			for (int i = 0; i < exp->subs.size(); i++)
			{
				flatten(exp->subs[i]);
			}
			flatten(new BExp(Syntax_Continue));
		}
		int exit = sequence.size();
		sequence.append(new BExp(Syntax_End, loop));
		if (BExpArray* exps = exp->value)
		{
			for (int i = 0; i < exps->size(); i++)
			{
				BExp* low = exps->at(i);
				if (low->syntax == Syntax_Break)
				{
					low->value = exit;
				}
				if (low->syntax == Syntax_Continue)
				{
					low->value = loop;
					continue;
				}
			}
		}
		exp->value = exit;
		exp->params.clear();
		exp->subs.clear();
		break;
	}
	case Syntax_For:
	{
		int begin = sequence.size();
		sequence.append(new BExp(Syntax_Begin, begin));
		flatten(exp->params.first());
		int loop = sequence.size();
		{
			sequence.append(new BExp(Syntax_Begin, loop));
			flatten(exp->params[1]);
			sequence.append(exp);
			for (int i = 0; i < exp->subs.size(); i++)
			{
				flatten(exp->subs[i]);
			}
			sequence.append(new BExp(Syntax_End, loop));
		}
		flatten(exp->params[2]);
		sequence.append(new BExp(Syntax_None, loop));
		int exit = sequence.size();
		sequence.append(new BExp(Syntax_End, begin));
		if (BExpArray* exps = exp->value)
		{
			for (int i = 0; i < exps->size(); i++)
			{
				BExp* low = exps->at(i);
				if (low->syntax == Syntax_Break)
				{
					low->value = exit;
				}
				if (low->syntax == Syntax_Continue)
				{
					low->value = loop;
					continue;
				}
			}
		}
		exp->value = exit;
		exp->params.clear();
		exp->subs.clear();
		break;
	}
	case Syntax_Break:
	case Syntax_Continue:
	{
		for (int i = sequence.size() - 1; i >= 0; i--)
		{
			BExp* up = sequence[i];
			if (up->syntax == Syntax_While || up->syntax == Syntax_For)
			{
				BExpArray& exps = up->value.fill<BExpArray>();
				exps.append(exp);
				break;
			}
		}
		sequence.append(exp);
		break;
	}
	case Syntax_Function:
	{
		sequence.append(exp);
		for (int i = 0; i < exp->params.size(); i++)
		{
			exp->params[i]->info.clear();
		}
		for (int i = 0; i < exp->subs.size(); i++)
		{
			flatten(exp->subs[i]);
		}
		int retpos = sequence.size() - 1;
		for (int i = retpos - 1; i >= 0; i--)
		{
			BExp* sub = sequence[i];
			if (sub == exp)
				break;
			if (sub->syntax == Syntax_Return)
				sub->value = retpos;
		}
		exp->subs.clear();
		break;
	}
	case Syntax_Method:
	{
		sequence.append(exp);
		for (int i = 0; i < exp->subs.size(); i++)
		{
			flatten(exp->subs[i]);
		}
		int retpos = sequence.size() - 1;
		for (int i = retpos - 1; i >= 0; i--)
		{
			BExp* sub = sequence[i];
			if (sub == exp)
				break;
			if (sub->syntax == Syntax_Return)
				sub->value = retpos;
		}
		exp->subs.clear();
		break;
	}
	default:
		break;
	}
}
void member_BScript::link()
{
	BString type;
	BString name;
	for (int i = 0; i < sequence.size(); i++)
	{
		BExp* exp = sequence[i];
		if (exp->syntax == Syntax_Call)
		{
			if (exp->name.contain(':'))
			{
				int split = exp->name.word(type, 0);
				BClass* cls = boss->findClass(type);
				if (cls == 0)
				{
					errorMessage(exp) << "Link : class " << type << " is undefined.";
					boss->emit(Signal_Message, message);
					continue;
				}
				exp->name.substr(name, split + 2);
				Method* method = class_member(cls)->methodMap(name);
				if (method == 0)
				{
					errorMessage(exp) << "Link : method " << exp->name << " is lost.";
					boss->emit(Signal_Message, message);
					continue;
				}
				exp->value = method;
			}
			else
			{
				Function* function = findFunction(exp->name);
				if (function == 0)
				{
					errorMessage(exp) << "Link : function " << exp->name << " is lost.";
					boss->emit(Signal_Message, message);
					continue;
				}
				exp->value = function;
			}
			continue;
		}
		if (exp->syntax == Syntax_Opera)
		{
			int split = exp->name.word(type, 0);
			if (type.empty())
			{
				errorMessage(exp) << "Link : operator " << exp->name << " is missed.";
				boss->emit(Signal_Message, message);
				continue;
			}
			BClass* cls = boss->findClass(type);
			if (cls == 0)
			{
				errorMessage(exp) << "Link : class " << type << " is undefined.";
				boss->emit(Signal_Message, message);
				continue;
			}
			exp->name.substr(name, split + 2);
			Method* method = class_member(cls)->methodMap(name);
			if (method == 0)
			{
				errorMessage(exp) << "Link : operator " << exp->name << " is lost.";
				boss->emit(Signal_Message, message);
				continue;
			}
			exp->value = method;
		}
	}
}
void member_BScript::debug(BExp* exp)
{
	if (current < sequence.size())
	{
		if (command.empty())
		{
			if (exp->info.size())
			{
				if (breakpointSet.contain(exp->info))
				{
					breaked = true;
					boss->emit(Signal_Breaked, exp->info);
				}
			}
			if (!breaked)
			{
				for (int i = 0; i < breakpointSet.size(); i++)
				{
					const BString& breakpoint = breakpointSet[i];
					if (breakpoint.contain(':'))
						continue;
					int number = breakpoint.toInt();
					if (number == current)
					{
						breaked = true;
						boss->emit(Signal_Breaked, breakpoint);
						break;
					}
				}
			}
		}
		else
		{
			if (command.contain(':'))
			{
				if (exp->info.size())
				{
					if (command == exp->info)
					{
						breaked = true;
						boss->emit(Signal_Breaked, command);
						command.reset();
					}
				}
			}
			else if (command == "step")
			{
				breaked = true;
				command = current;
				boss->emit(Signal_Breaked, command);
				command.reset();
			}
			else
			{
				int number = command.toInt();
				if (number == current)
				{
					breaked = true;
					boss->emit(Signal_Breaked, command);
					command.reset();
				}
			}
		}
		if (breaked)
		{
#ifdef linux
			pthread_t handle = pthread_self();
#endif
#ifdef _WIN32
			HANDLE handle = GetCurrentThread();
#endif
			if (app_handle == handle)
			{
				while (!app_done)
				{
					if (boss->trylock())
					{
						if (!breaked)
						{
							boss->unlock();
							break;
						}
						boss->unlock();
					}
					App_CycleBegin();
					App_Event();
					App_Update();
					App_Frame();
					App_CycleEnd();
				}
			}
			else
			{
				pausedHandle = handle;
#ifdef linux
				pthread_cond_wait(&thread_cond, &thread_mutex);
#endif
#ifdef _WIN32
				DWORD ret = SuspendThread(handle);
#endif
				pausedHandle = 0;
			}
		}
	}
}
void member_BScript::debugResume()
{
#ifdef linux
	::pthread_cond_signal(&thread_cond);
#else
	::ResumeThread(pausedHandle);
#endif
}

int member_BScript::perform(BExp* exp)
{
	switch (exp->syntax)
	{
	case Syntax_None:
	{
		int next = exp->value;
		return next;
	}
	case Syntax_Include:
	{
		return current + 1;
	}
	case Syntax_Value:
	{
		BVariant& var = stack.push();
		var.setType(exp->type);
		var.setValue(exp->value);
		return current + 1;
	}
	case Syntax_Name:
	{
		if (BVariant* ptr = findVariant(exp->name))
		{
			BVariant& var = stack.push();
			var.setType(ptr->type());
			var.setValue(ptr);
			return current + 1;
		}
		errorMessage(exp) << "named variant lost : " << exp->name << '.';
		boss->emit(Signal_Error, message);
		return current + 1;
	}
	case Syntax_Self:
	{
		for (int i = stack.size() - 1; i >= global; i--)
		{
			BVariant& var = stack[i];
			if (CallInfo* cinfo = var.value())
			{
				if (!cinfo->self)
					break;
				BClass* self = cinfo->self;
				if (exp->name.empty())
				{
					BVariant& var = stack.push();
					var.setType(self->name());
					var.setValue(self);
					return current + 1;
				}
				BString name;
				BVariant* ptr = 0;
				const char* cstr = exp->name.cstr();
				for (int i = 0; i < exp->name.size(); i++)
				{
					i = exp->name.word(name, i);
					if (name == '.')
						continue;
					auto it = class_member(self)->variantMap.find(name);
					if (it.empty())
						break;
					ptr = &(it.value());
				}
				if (!ptr)
					break;
				BVariant& var = stack.push();
				var.setType(ptr->type());
				var.setValue(ptr);
				return current + 1;
			}
		}
		errorMessage(exp) << "self named variant lost : " << exp->name << '.';
		boss->emit(Signal_Error, message);
		return current + 1;
	}
	case Syntax_Decl:
	{
		if (exp->type.endWith('&') || exp->type.endWith('*'))
		{
			const BString& name = exp->value;
			BVariant* ptr = findVariant(name);
			if (!ptr)
			{
				errorMessage(exp) << "declare failed : " << exp->name << " = " << name << '.';
				boss->emit(Signal_Error, message);
				return sequence.size();
			}
			BVariant& var = stack.push();
			var.setType(exp->type);
			var.setName(exp->name);
			if (ptr->value().is<BVariant*>())
				var.setValue(ptr->value());
			else
				var.setValue(ptr);
			return current + 1;
		}
		BVariant& var = stack.push();
		var.setType(exp->type);
		var.setName(exp->name);
		BClass* cls = boss->findClass(exp->type);
		if (!class_member(cls)->meta)
		{
			BClass* obj = new BClass();
			for (auto it = class_member(cls)->variantMap.begin(); it.valid(); ++it)
			{
				const BString& name = it.key();
				const BVariant& var0 = it.value();
				BVariant& var = class_member(obj)->variantMap[name];
				var.setType(var0.type());
				var.setName(var0.name());
			}
			for (auto it = class_member(cls)->methodMap.begin(); it.valid(); ++it)
			{
				class_member(obj)->methodMap.insert(it.key(), it.value());
			}
			for (int i = 0; i < class_member(cls)->inherits.size(); i++)
			{
				BClass* up = class_member(cls)->inherits[i]->value;
				for (auto it = class_member(up)->variantMap.begin(); it.valid(); ++it)
				{
					const BString& name = it.key();
					const BVariant& var0 = it.value();
					BVariant& var = class_member(obj)->variantMap[name];
					var.setType(var0.type());
					var.setName(var0.name());
				}
				for (auto it = class_member(up)->methodMap.begin(); it.valid(); ++it)
				{
					class_member(obj)->methodMap.insert(it.key(), it.value());
				}
			}
			var.setValue(obj);
		}
		return current + 1;
	}
	case Syntax_Opera:
	case Syntax_Call:
	{
		if (Method* method = exp->value)
		{
			if (method->cfunc)
			{
				int top = stack.size() - method->params.size();
				BVariant* argv = stack.data() + top - 1;
				for (int i = 0; i < method->params.size(); i++)
				{
					argv[1 + i].setName(method->params[i].name());
				}
				int argc = method->params.size() + 1;
				if (!method->cfunc(argc, argv))
				{
					errorMessage(exp) << "call funtion failed : " << exp->name << ':' << argv->name() << '.';
					boss->emit(Signal_Error, message);
				}
				if (method->type.size())
				{
					argv->setType(method->type);
					argv->setName(BString());
				}
				stack.back(top);
				return current + 1;
			}
			CallInfo* cinfo = new CallInfo();
			cinfo->type = method->type;
			cinfo->pos = current + 1;
			cinfo->top = stack.size() - method->params.size();
			cinfo->self = stack[cinfo->top - 1];
			BVariant& var = stack.push();
			var.setValue(cinfo);
			var.setType("call");
			BExp* sfunc = method->value;
			var.setName(sfunc->name);
			return method->line;
		}
		Function* function = exp->value;
		if (function->cfunc)
		{
			int top = stack.size() - function->params.size();
			BVariant* argv = stack.data() + top - 1;
			for (int i = 0; i < function->params.size(); i++)
			{
				argv[1 + i].setName(function->params[i].name());
			}
			int argc = function->params.size() + 1;
			if (!function->cfunc(argc, argv))
			{
				errorMessage(exp) << "call funtion failed : " << exp->name << ':' << argv->name() << '.';
				boss->emit(Signal_Error, message);
			}
			if (function->type.size())
			{
				argv->setType(function->type);
				argv->setName(BString());
			}
			stack.back(top);
			return current + 1;
		}
		CallInfo* cinfo = new CallInfo();
		cinfo->type = function->type;
		cinfo->pos = current + 1;
		cinfo->top = stack.size() - function->params.size();
		BVariant& var = stack.push();
		var.setValue(cinfo);
		var.setType("call");
		var.setName(function->sfunc->name);
		return function->line;
	}
	case Syntax_Function:
	case Syntax_Method:
	{
		CallInfo& cinfo = stack.last().value();
		BVariant* argv = stack.data() + cinfo.top;
		for (int i = 0; i < exp->params.size(); i++)
		{
			argv[i].setName(exp->params[i]->name);
		}
		return current + 1;
	}
	case Syntax_If:
	{
		bool condition = stack.last();
		if (condition)
			return current + 1;
		int pos = exp->value;
		return pos;
	}
	case Syntax_Else:
	{
		return exp->value;
	}
	case Syntax_For:
	{
		bool condition = stack.last();
		if (condition)
			return current + 1;
		int pos = exp->value;
		return pos;
	}
	case Syntax_While:
	{
		bool condition = stack.last();
		if (condition)
			return current + 1;
		int pos = exp->value;
		return pos;
	}
	case Syntax_Continue:
	{
		int line = exp->value;
		for (int i = stack.size() - 1; i >= 0; i--)
		{
			BVariant& var = stack[i];
			if (var.value().is<CallInfo>())
				break;
			BExp* begin = var.value();
			if (begin && begin->value == line)
			{
				stack.back(i);
				return line;
			}
		}
		errorMessage(exp) << "continue failed : begin " << line + 1 << " lost.";
		boss->emit(Signal_Error, message);
		return sequence.size();
	}
	case Syntax_Break:
	{
		int pos = exp->value;
		return pos;
	}
	case Syntax_Return:
	{
		for (int i = stack.size() - 1; i >= 0; i--)
		{
			BVariant& var = stack[i];
			if (CallInfo* cinfo = var.value())
			{
				if (cinfo->type.size())
				{
					BVariant* res = stack.data() + cinfo->top - 1;
					res->setType(cinfo->type);
					res->setName(BString());
					BVariant& var = stack.last();
					if (BVariant* ptr = var.value())
						res->setValue(ptr->value());
					else
						res->setValue(var.value());
				}
			}
		}
		int pos = exp->value;
		return pos;
	}
	case Syntax_Begin:
	{
		for (int i = stack.size() - 1; i >= 0; i--)
		{
			BVariant& var = stack[i];
			if (var.value().is<BExp>())
				break;
			if (var.name().empty())
				stack.back(i);
			else
				break;
		}
		stack.push(exp);
		return current + 1;
	}
	case Syntax_End:
	{
		if (exp->value.empty())
		{
			for (int i = stack.size() - 1; i >= 0; i--)
			{
				BVariant& var = stack[i];
				BExp* begin = var.value();
				if (!begin)
					continue;
				if (begin->syntax != Syntax_Begin)
					continue;
				if (CallInfo* cinfo = stack(i - 1).value())
				{
					int back = cinfo->pos;
					stack.back(cinfo->top);
					return back;
				}
				stack.back(i);
				return current + 1;
			}
			errorMessage(exp) << "end failed : begin lost.";
			boss->emit(Signal_Error, message);
			return sequence.size();
		}
		int line = exp->value;
		for (int i = stack.size() - 1; i >= 0; i--)
		{
			BVariant& var = stack[i];
			if (var.value().is<CallInfo>())
				break;
			BExp* begin = var.value();
			if (begin && begin->value == line)
			{
				stack.back(i);
				return current + 1;
			}
		}
		errorMessage(exp) << "end failed : begin " << line + 1 << " lost.";
		boss->emit(Signal_Error, message);
		return sequence.size();
	}
	default:
		break;
	}
	error = true;
	return -1;
}
BVariant* member_BScript::variant(const BString& name)
{
	for (int i = stack.size() - 1; i >= global; i--)
	{
		BVariant& var = stack[i];
		if (var.name() == name)
			return &var;
		if (CallInfo* cinfo = var.value())
		{
			while (--i >= cinfo->top)
			{
				BVariant& var = stack[i];
				if (var.name() == name)
					return &var;
			}
			break;
		}
	}
	for (int i = 0; i < global; i++)
	{
		BVariant& var = stack[i];
		if (var.name() == name)
			return &var;
	}
	return 0;
}
BVariant* member_BScript::findVariant(const BString& path)
{
	const char* cstr = path.cstr();
	for (int i = 0; i < path.size(); i++)
	{
		if (cstr[i] == '.')
		{
			BString name;
			path.substr(name, 0, i);
			BVariant* ptr = variant(name);
			if (!ptr)
				return 0;
			while (i < path.size())
			{
				i = path.word(name, i);
				if (name == '.')
					continue;
				BClass* obj = *ptr;
				if (!obj)
					return 0;
				auto it = class_member(obj)->variantMap.find(name);
				if (it.empty())
					return 0;
				ptr = &(it.value());
			}
			return ptr;
		}
	}
	if (BVariant* ptr = variant(path))
		return ptr;
	return 0;
}
Function* member_BScript::findFunction(const BString& name)
{
	if (Function* func = presets.functionMap(name))
		return func;
	if (Function* func = functionMap(name))
		return func;
	return 0;
}
